﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// This class containing all methods and enums used for working with projects
/// </summary>
public class ProjectManagement
{
    /// <summary>
    /// current logged in user
    /// </summary>
    User currentUser;

    /// <summary>
    /// current working project
    /// </summary>
    Project currentProject;

    /// <summary>
    /// pass the current logged in user to this instance
    /// </summary>
    /// <param name="currentUser">current logged in user</param>
    public ProjectManagement(User currentUser)
    {
        this.currentUser = currentUser;
        this.currentProject = null;
    }

    /// <summary>
    /// pass the current logged in user and current working project to this instance
    /// </summary>
    /// <param name="currentUser">current logged in user</param>
    /// <param name="currentProject">current working project</param>
    public ProjectManagement(User currentUser, Project currentProject)
    {
        this.currentUser = currentUser;
        this.currentProject = currentProject;
    }

    /// <summary>
    /// Create a new project
    /// </summary>
    /// <param name="name">Name of the new project</param>
    /// <param name="description">Short description</param>
    /// <param name="customMessage">Custom message to be displayed on top of project page</param>
    /// <returns>new Project ID if project creation succeeds, otherwise -1 with thrown exception</returns>
    public int AddProject(string name, string description, string customMessage)
    {
        try
        {
            // create a new project
            // need not define projectID as it is automatically added by database
            Project newProject = new Project();

            // set basic fields
            newProject.Name = name;
            newProject.Description = description;
            newProject.CustomMessage = customMessage;

            // project status is now open
            newProject.IsActive = true;

            // add new project to database
            ApplicationGlobalVariables.KillDaBugsDatabase.Projects.InsertOnSubmit(newProject);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event of creating new project
            Logging.AddLog(Logging.LogEvent.AddProject, newProject, currentUser.Username, null);

            // if everything alright
            return newProject.ProjectId;
        }
        catch (Exception ex)
        {
            return -1;
            throw ex;
        }
    }

    /// <summary>
    /// Update project's info. To close a project, use SetProjectStatus
    /// </summary>
    /// <param name="projectId">ID of the project to be updated</param>
    /// <param name="name">New name of project</param>
    /// <param name="description">New description</param>
    /// <param name="customMessage">New custome message</param>
    /// <returns>true if project updates successfully, otherwise false with thrown exception</returns>
    public bool UpdateProjectInfo(int projectId, string name, string description, string customMessage)
    {
        try
        {
            Project edittedProject = GetProject(projectId);

            // update fields with new values
            edittedProject.Name = name;
            edittedProject.Description = description;
            edittedProject.CustomMessage = customMessage;

            // update to database
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event of updating project info
            Logging.AddLog(Logging.LogEvent.UpdateProjectInfo, edittedProject, currentUser.Username, null);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// Update current project's info. To close a project, use SetProjectStatus
    /// </summary>
    /// <param name="name">New name of project</param>
    /// <param name="description">New description</param>
    /// <param name="customMessage">New custome message</param>
    /// <returns>true if project updates successfully, otherwise false with thrown exception</returns>
    public bool UpdateProjectInfo(string name, string description, string customMessage)
    {
        try
        {
            // update fields with new values
            currentProject.Name = name;
            currentProject.Description = description;
            currentProject.CustomMessage = customMessage;

            // update to database
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event of updating project info
            Logging.AddLog(Logging.LogEvent.UpdateProjectInfo, currentProject, currentUser.Username, null);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// close or open a project
    /// </summary>
    /// <param name="projectId">ID of the project to update status</param>
    /// <param name="isActive">true of new status is Active, false if new status is Closed</param>
    /// <returns>true if new status set successfully, otherwise false</returns>
    public bool SetProjectStatus(int projectId, bool isActive)
    {
        try
        {
            Project edittedProject = GetProject(projectId);

            // update status
            edittedProject.IsActive = isActive;

            // update to database
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event of updating project info
            Logging.AddLog(Logging.LogEvent.SetProjectStatus, edittedProject, currentUser.Username, null);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// close or open current project
    /// </summary>
    /// <param name="isActive">true of new status is Active, false if new status is Closed</param>
    /// <returns>true if new status set successfully, otherwise false</returns>
    public bool SetProjectStatus(bool isActive)
    {
        try
        {
            // update status
            currentProject.IsActive = isActive;

            // update to database
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event of updating project info
            Logging.AddLog(Logging.LogEvent.SetProjectStatus, currentProject, currentUser.Username, null);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// delete an existing project
    /// </summary>
    /// <param name="projectId">ID of the project to be deleted</param>
    /// <returns>true if project deletion succeeds, otherwise false with exeption thrown</returns>
    public bool DeleteProject(int projectId)
    {
        try
        {
            Project deletedProject = GetProject(projectId);

            // delete this project from Project table
            ApplicationGlobalVariables.KillDaBugsDatabase.Projects.DeleteOnSubmit(deletedProject);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // delete any log related to this project
            Logging.ClearLogProject(deletedProject.ProjectId);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// delete current project
    /// </summary>
    /// <returns>true if project deletion succeeds, otherwise false with exeption thrown</returns>
    public bool DeleteProject()
    {
        try
        {
            ApplicationGlobalVariables.KillDaBugsDatabase.Projects.DeleteOnSubmit(currentProject);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // delete any log related to this project
            Logging.ClearLogProject(currentProject.ProjectId);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// assign user to a project
    /// </summary>
    /// <param name="toUsername">username of assigned user</param>
    /// <param name="projectId">ID of the project to grant access to user</param>
    /// <returns>true if assignment succeeds, otherwise false with exeption thrown</returns>
    public bool AssignUserToProject(string toUsername, int projectId)
    {
        try
        {
            Project project = GetProject(projectId);

            User_Project newUserToProjectAssignment = new User_Project();
            newUserToProjectAssignment.Username = toUsername;
            newUserToProjectAssignment.ProjectId = project.ProjectId;
            ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.InsertOnSubmit(newUserToProjectAssignment);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event
            Logging.AddLog(Logging.LogEvent.AssignUserToProject, project, currentUser.Username, toUsername);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// assign a user to current project
    /// </summary>
    /// <param name="toUsername">username of assigned user</param>
    /// <returns>true if assignment succeeds, otherwise false with exeption thrown</returns>
    public bool AssignUserToProject(string toUsername)
    {
        try
        {
            User_Project newUserToProjectAssignment = new User_Project();
            newUserToProjectAssignment.Username = toUsername;
            newUserToProjectAssignment.ProjectId = currentProject.ProjectId;
            ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.InsertOnSubmit(newUserToProjectAssignment);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event
            Logging.AddLog(Logging.LogEvent.AssignUserToProject, currentProject, currentUser.Username, toUsername);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// revoke access of user to a project
    /// </summary>
    /// <param name="toUsername">username of user to revoke access</param>
    /// <param name="project">project to revoke the access from</param>
    /// <returns>true if unassignment succeeds, otherwise false with exeption thrown</returns>
    public bool UnassignUserFromProject(string toUsername, int projectId)
    {
        try
        {
            Project project = GetProject(projectId);

            User_Project userToProjectUnassignment = ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.Single(i => i.Username == toUsername && i.ProjectId == project.ProjectId);
            ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.DeleteOnSubmit(userToProjectUnassignment);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event
            Logging.AddLog(Logging.LogEvent.UnassignUserFromProject, project, currentUser.Username, toUsername);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// revoke access of user to current project
    /// </summary>
    /// <param name="toUsername">username of user to revoke access</param>
    /// <returns>true if unassignment succeeds, otherwise false with exeption thrown</returns>
    public bool UnassignUserFromProject(string toUsername)
    {
        try
        {
            User_Project userToProjectUnassignment = ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.Single(i => i.Username == toUsername && i.ProjectId == currentProject.ProjectId);
            ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.DeleteOnSubmit(userToProjectUnassignment);
            ApplicationGlobalVariables.KillDaBugsDatabase.SubmitChanges();

            // log this event
            Logging.AddLog(Logging.LogEvent.UnassignUserFromProject, currentProject, currentUser.Username, toUsername);

            // if everything alright
            return true;
        }
        catch (Exception ex)
        {
            return false;
            throw ex;
        }
    }

    /// <summary>
    /// returns a list of Projects that current user is assigned to
    /// </summary>
    /// <returns>list of Projects the user is assigned to</returns>
    public List<Project> ViewProject()
    {
        try
        {
            return (List<Project>)ApplicationGlobalVariables.KillDaBugsDatabase.User_Projects.Where(i => i.Username == currentUser.Username).Select(i => i.Project);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    /// <summary>
    /// get Project object of a project ID
    /// </summary>
    /// <param name="projectId">project ID to get Project object</param>
    /// <returns>Project object</returns>
    public static Project GetProject(int projectId)
    {
        try
        {
            return ApplicationGlobalVariables.KillDaBugsDatabase.Projects.Single(i => i.ProjectId == projectId);
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}